package com.sp.system.user.core.zookeeper;

import lombok.extern.slf4j.Slf4j;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * @Describle zookeeper 工具类
 */
@Slf4j
@Component
public class ZookeeperClient {

    @Value("${spring.application.name}")
    private String pcServerName; // 服务名
    @Value("${spring.cloud.zookeeper.connect-string}")
    private String pcConnectString; // zk连接地址

    public static String serverName;  // 服务名
    public static String connectString; // zk连接地址

    private final static int sessionTimeoutMs = 5000; // 会话超时时间
    private final static int maxRetries = 3; // 重连次数
    private final static int waitTime = 1000; // 等待时间
    /**
     * zkL连接对象
     */
    private static CuratorFramework curatorFramework;

    private ZookeeperClient() {

    }
    private static class InstanceHolder {
        private static ZookeeperClient zookeeperClient = new ZookeeperClient();
    }
    @PostConstruct
    private void init(){

        this.connectString = pcConnectString;
        this.serverName = pcServerName;
       log.debug("zk连接名，连接地址[{}][{}]",connectString,serverName);
    }
    /**
     * 单例获取对象
     *
     * @return
     */
    public static ZookeeperClient getInstance() {
        return InstanceHolder.zookeeperClient;
    }

    /**
     * 开启连接
     */
    public void startConnection() {
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(waitTime, maxRetries);
        curatorFramework = CuratorFrameworkFactory
                .builder()
                .connectString(connectString)
                .sessionTimeoutMs(sessionTimeoutMs)
                .retryPolicy(retryPolicy)
                .build();

        curatorFramework.start();
        log.debug("[zookeeper]>>>>>>>>>>>>> {{}} has been successfully connected to zookeeper ...",serverName);
    }
    /**
     * 关闭连接
     */
    public void closeZooKeeper() {
        if (curatorFramework != null) {
            curatorFramework.close();
            log.debug("[zookeeper]>>>>>>>>>>>>> {{}} has been successfully closed the zookeeper connection  ...",serverName);
        }
    }

    /**
     * @Describle 创建节点
     *  1.PERSISTENT--持久型
     *  2.PERSISTENT_SEQUENTIAL--持久顺序型
     *  3.EPHEMERAL--临时型
     *  4.EPHEMERAL_SEQUENTIAL--临时顺序型
     *
     * @param path
     * @param content
     * @param createMode
     * @return
     */
    public boolean creatNode(String path,String content, CreateMode createMode){
        try {
            curatorFramework.create()
                    .creatingParentsIfNeeded()
                    .withMode(createMode)
                    .withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE)
                    .forPath(path, content.getBytes());
            return true;
        } catch (Exception e) {
           log.error("zk 创建节点失败",e);
           return false;
        }
    }

    /**
     * @Describle 删除节点
     * @param path
     * @return
     */
    public boolean deleteNode(String path){
        try {
            curatorFramework.delete().forPath(path);
            return true;
        } catch (Exception e) {
            log.error("zk 删除节点失败",e);
            return false;
        }
    }

    /**
     * 删除节点和子节点
     *
     * @param path
     */
    public void deleteAllChildrenNode(String path) {
        try {
            Stat stat = new Stat();
            curatorFramework.getData().storingStatIn(stat).forPath(path);
            curatorFramework.delete().deletingChildrenIfNeeded().withVersion(stat.getVersion()).forPath(path);
        } catch (Exception e) {
            log.error("zk节点及子节点删除失败", e);
        }
    }

    /**
     *  更新节点数据
     * @param path
     * @param data
     */
    public void updateNode(String path, String data) {
        try {
            curatorFramework.setData().forPath(path, data.getBytes());
        } catch (Exception e) {
            log.error("更新节点数据失败" ,e);
        }
    }

    /**
     * 判断节点是否存在
     *
     * @param path
     * @return
     */
    public boolean checkNode(String path) {
        try {
            Stat stat = curatorFramework.checkExists().forPath(path);
            return stat != null;
        } catch (Exception e) {
            log.error("判断节点数据失败" ,e);
            return false;
        }
    }

}
